package com.cqjtu.eecs.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cqjtu.eecs.entity.*;
import com.cqjtu.eecs.entity.dto.CurrUserInfo;
import com.cqjtu.eecs.entity.dto.UserDTO;
import com.cqjtu.eecs.entity.params.user.UserParams;
import com.cqjtu.eecs.entity.vo.UserVO;
import com.cqjtu.eecs.exception.NotFoundException;
import com.cqjtu.eecs.exception.ParamsErrorException;
import com.cqjtu.eecs.mapper.*;
import com.cqjtu.eecs.service.IMajorService;
import com.cqjtu.eecs.service.IStudentService;
import com.cqjtu.eecs.service.ITeacherService;
import com.cqjtu.eecs.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cqjtu.eecs.utils.Assert;
import com.cqjtu.eecs.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author     luojun
 * @since 2022-03-04
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private RoleUserMapper roleUserMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private RolePermissionMapper rolePermissionMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserPermissionMapper userPermissionMapper;
    @Autowired
    private RedisService redisService;

    @Autowired
    private IStudentService studentService;

    @Autowired
    private ITeacherService teacherService;

    @Autowired
    private MajorMapper majorMapper;

    @Autowired
    private NaturalClassMapper naturalClassMapper;

    /**
     * 通过uid获取用户角色
     * @param uid 用户id
     * @return  用户角色list
     */
    @Override
    public List<Role> listRoleByUid(Integer uid) {
        List<RoleUser> roleUserList = roleUserMapper
                .selectList(new LambdaQueryWrapper<RoleUser>().eq(RoleUser::getUid, uid));
        // 结果为空时返回的是一个空list，不是null,可用isEmpty判断
        if (roleUserList.isEmpty())
            return new ArrayList<Role>();
        List<Role> roles = roleMapper.selectBatchIds(roleUserList.stream()
                .map(RoleUser::getRoleId).collect(Collectors.toList()));
        return roles;
    }

    /**
     * 通过uid获取用户权限
     * @param uid   用户id
     * @return  用户权限list
     */
    @Override
    public List<Permission> listPermissionByUid(Integer uid) {
        List<Role> roles = this.listRoleByUid(uid);
        HashSet<Integer> permissionIdSet = new HashSet<>();
        List<Integer> roleIdList = roles.stream().map(Role::getRoleId).collect(Collectors.toList());
        if (!roleIdList.isEmpty()){
            // 获取角色对应的权限idList
            permissionIdSet.addAll(
                    new HashSet<>(rolePermissionMapper.listPermissionIdListByRoleIdList(roleIdList)));
        }
        // 获取用户的特殊权限
        List<UserPermission> userPermissions = userPermissionMapper
                .selectList(new LambdaQueryWrapper<UserPermission>()
                .eq(UserPermission::getUid, uid));
        if (userPermissions.isEmpty()){
            permissionIdSet.addAll(userPermissions
                    .stream().map(UserPermission::getId).collect(Collectors.toSet()));
        }
        if (permissionIdSet.isEmpty())
            return new ArrayList<Permission>();
        return permissionMapper.selectBatchIds(permissionIdSet);
    }

    /**
     * 添加用户
     * @param userParams
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveUser(UserParams userParams) {
        if (null != this.getOne(
                new LambdaQueryWrapper<User>()
                        .eq(User::getUsername, userParams.getUserName()))) // 用户已存在
            return false;
        User user = new User();
        user.setPassword(new BCryptPasswordEncoder().encode(userParams.getPassword()));
        user.setUsername(userParams.getUserName());
        if (!save(user))
            return false;
        // 插入角色
        if (userParams.getRoleNames().isEmpty())
            return true;
        List<Role> roles = roleMapper.listRoleByNameList(userParams.getRoleNames());
        Set<Integer> roleIdList = roles.stream().map(Role::getRoleId).collect(Collectors.toSet());
        HashSet<RoleUser> roleUsers = new HashSet<>();
        roleIdList.forEach(item->{
            roleUsers.add(new RoleUser(user.getUid(), item));
        });
        roleUserMapper.saveBatch(new ArrayList<>(roleUsers));
        return true;
    }

    /**
     * 分页获取用户信息
     * @param page 当前页
     * @param pageSize 当前页大小
     * @return
     */
    @Override
    public UserVO listUserByPage(Long page, Long pageSize) {
        Page page1 = new Page(page, pageSize);
        Page page2 = userMapper.selectPage(page1, null);
        List<User> users = (List<User>)page2.getRecords();

        ArrayList<UserDTO> userDTOS = new ArrayList<>();
        users.forEach(item->{
            userDTOS.add(new UserDTO(item.getUid(), item.getUsername(), roleMapper.listUserRole(item.getUid())));
        });
        return new UserVO(page2.getTotal(), page2.getCurrent(), page2.getSize(), userDTOS);
    }

    /**
     * 分页模糊查询
     * @param page  当前页
     * @param pageSize  当前页大小
     * @param name  模糊查询条件
     * @return
     */
    @Override
    public UserVO listUserPageByName(Long page, Long pageSize, String name) {
        Page page1 = new Page(page, pageSize);
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.like("username", name);
        Page page2 = userMapper.selectPage(page1, userQueryWrapper);

        List<User> users = (List<User>)page2.getRecords();
        ArrayList<UserDTO> userDTOS = new ArrayList<>();
        users.forEach(item->{
            userDTOS.add(new UserDTO(item.getUid(), item.getUsername(),roleMapper.listUserRole(item.getUid())));
        });

        return new UserVO(page2.getTotal(),page2.getCurrent(), page2.getSize(), userDTOS);
    }

    /**
     * 获取用户的角色list
     * @param name  用户名
     * @return
     */
    @Override
    public List<String> listRoleByName(String name) {
        ArrayList<String> strings = new ArrayList<>();
        // 获取用户
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, name));
        Assert.notNull(user, new NotFoundException("Not find the user"));
        List<RoleUser> roleUsers = roleUserMapper
                .selectList(new LambdaQueryWrapper<RoleUser>().eq(RoleUser::getUid, user.getUid()));
        if (roleUsers.isEmpty())
            return strings;
        List<Integer> roleIdList = roleUsers.stream().map(RoleUser::getRoleId).collect(Collectors.toList());
        List<Role> roles = roleMapper.listRoleByIdList(roleIdList);
        roles.forEach(item->{
            strings.add(item.getRoleName());
        });
        return strings;
    }

    /**
     * 修改用户的角色
     * @param name  用户名
     * @param roles 用户角色
     * @return
     */
    @Override
    public boolean updateUserRole(String name, List<String> roles) {
        // 获取用户
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, name));
        // 获取用户的角色
        List<String> strings = this.listRoleByName(name);
        HashSet<String> newRole = new HashSet<>(roles);
        HashSet<String> oldRole = new HashSet<>(strings);
        newRole.removeAll(oldRole); // 需要添加的角色
        oldRole.removeAll(new HashSet<>(roles)); // 需要删除的角色
        if (!newRole.isEmpty()){
            // 添加角色
            // 获取角色idList
            List<Integer> roleIdList = roleMapper.listRoleByNameList(new ArrayList<>(newRole))
                    .stream().map(Role::getRoleId)
                    .collect(Collectors.toList());
            ArrayList<RoleUser> newRoleUsers = new ArrayList<>();
            roleIdList.forEach(item->{
                newRoleUsers.add(new RoleUser(user.getUid(), item));
            });
            if (roleUserMapper.saveBatch(newRoleUsers) == 0)
                return false;
        }
        if (!oldRole.isEmpty()){
            // 删除角色
            List<Integer> roleIdList = roleMapper.listRoleByNameList(new ArrayList<>(oldRole))
                    .stream().map(Role::getRoleId)
                    .collect(Collectors.toList());
            if (roleUserMapper.removeBatch(user.getUid(), roleIdList) == 0)
                return false;
        }
        redisService.remove(user.getUsername());
//        if (redisService.getString(user.getUsername()) != null){
//            // 修改成功之后需要在redis中更新用户的权限
//            // 需要在redis中删除权限
//            Set<GrantedAuthority> grantedAuthorities = this.listUserPermissionSet(user.getUid());
//            redisService.setEXString(user.getUsername(),
//                    JSON.toJSONString(grantedAuthorities),
//                    Integer.toUnsignedLong(JwtUtils.EXPIRATION));
//        }
        return true;
    }

    /**
     * 获取用户的权限集合
     * @param uid   用户id
     * @return
     */
    @Override
    public Set<GrantedAuthority> listUserPermissionSet(Integer uid) {
        Set<GrantedAuthority> authorities = new HashSet<>();
        List<Role> roles = this.listRoleByUid(uid);
        List<Permission> permissions = this.listPermissionByUid(uid);
        // 将角色放入集合,需要拼接ROLE_
        for (Role role:roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));
        }
        // 将权限放入集合
        for (Permission permission:permissions){
            authorities.add(new SimpleGrantedAuthority(permission.getName()));
        }
        return authorities;
    }

    /**
     * 为某个用户添加某个角色
     * @param uid 用户id
     * @param roleName  用户角色
     * @return
     */
    @Override
    public boolean addRoleToUser(Integer uid, String roleName) {
        // 获取对应的角色
        Role role = roleMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleName, roleName));
        Assert.notNull(role, new NotFoundException("Not find the role"));
        RoleUser roleUser = roleUserMapper.selectOne(new LambdaQueryWrapper<RoleUser>()
                .eq(RoleUser::getUid, uid)
                .eq(RoleUser::getRoleId, role.getRoleId()));
        if (roleUser == null){
            // 插入新角色
            if (roleUserMapper.insert(new RoleUser(uid, role.getRoleId()))>0){
                return true;
            }
            else{
                return false;
            }
        }
        return true;
    }

    /**
     * 获取当前登录用户信息
     * @param name
     * @return
     */
    @Override
    public CurrUserInfo getCurrentUserInfo(String name) {
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", name));
        if (user == null)
            throw new NotFoundException("用户不存在");

        CurrUserInfo userInfo = new CurrUserInfo();
        List<String> roleList = roleUserMapper.getCurrentUserRoleList(user.getUid());
        userInfo.setRoleList(roleList);

        for (String role : roleList) {
            if (role.equals("student")) {
                Student student = studentService.getOne(new QueryWrapper<Student>().eq("uid", user.getUid()));
                if (student != null) {
                    userInfo.setGrade(student.getGrade());
                    userInfo.setMajorCode(student.getMajorCode());
                }
            }

            if (role.equals("teacher")) {
                Teacher teacher = teacherService.getOne(new QueryWrapper<Teacher>().eq("uid", user.getUid()));
                if (teacher != null)
                    userInfo.setAcademyId(teacher.getAcademyId());
            }

            if (role.equals("major_manager")) {
                Teacher teacher = teacherService.getOne(new QueryWrapper<Teacher>().eq("uid", user.getUid()));
                if (teacher == null)
                    continue;
                Major major = majorMapper.selectOne(new QueryWrapper<Major>().eq("tid", teacher.getTid()));
                if (major != null)
                    userInfo.setMajorCode(major.getMajorCode());
            }

            if (role.equals("mentor")) {
                Teacher teacher = teacherService.getOne(new QueryWrapper<Teacher>().eq("uid", user.getUid()));
                if (teacher == null)
                    continue;
                List<NaturalClass> naturalClassList = naturalClassMapper.selectList(new QueryWrapper<NaturalClass>().eq("tid", teacher.getTid()));
                List<Integer> classIdList = new ArrayList<>();
                for (NaturalClass naturalClass : naturalClassList) {
                    classIdList.add(naturalClass.getNcId());
                }
                if (naturalClassList != null) {
                    userInfo.setMajorCode(naturalClassList.get(0).getMajorCode());
                    userInfo.setGrade(naturalClassList.get(0).getGrade());
                    userInfo.setNcIdList(classIdList);
                }

            }
        }
        return userInfo;
    }


    @Override
    public User selectUserByStudentCode(String studentCode) {
        return userMapper.selectUserByStudentCode(studentCode);
    }

    /**
     * 根据用户名和角色名删除用户的某个角色
     * @param username
     * @param roleName
     * @return
     */
    @Override
    public Boolean removeRoleByUsername(String username, String roleName) {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        Assert.notNull(user, new NotFoundException("Not find the user:"+username));
        Role role = roleMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleName, roleName));
        Assert.notNull(role, new NotFoundException("Not find the role:" + roleName));
        roleUserMapper.delete(new LambdaUpdateWrapper<RoleUser>()
                .eq(RoleUser::getUid, user.getUid())
                .eq(RoleUser::getRoleId, role.getRoleId()));
        // 删除缓存
        redisService.remove(username);
        return true;
    }

    /**
     * 判断某个用户是否拥有某个角色
     * @param username
     * @param roleName
     * @return
     */
    @Override
    public Boolean hasRole(String username, String roleName) {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        Assert.notNull(user, new NotFoundException("Not find the user:"+username));
        Role role = roleMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleName, roleName));
        Assert.notNull(role, new NotFoundException("Not find the role:" + roleName));
        RoleUser roleUser = roleUserMapper.selectOne(new LambdaQueryWrapper<RoleUser>()
                .eq(RoleUser::getUid, user.getUid()).eq(RoleUser::getRoleId, role.getRoleId()));
        if (roleUser == null)
            return false;
        return true;
    }
}
